//------------------------------------------------------------------------------
///	\file rb-test.c
///
///	\brief
///		ring buffer test harness
///
//	$Id: rb-test.c 299 2014-09-27 07:34:40Z ac.verbeck@gmail.com $
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//	The MIT License (MIT)
//
//	Copyright (c) 2014 A.C. Verbeck
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.

//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <popt.h>

#include <stdint.h>																//	Standard int types
#include <stdbool.h>															//	Standard bool type

#include "bi.h"
#include "ringbuff.h"

//------------------------------------------------------------------------------
// Local defines
//------------------------------------------------------------------------------
#define OPT_SIMPLE			0x0001
#define OPT_FULL			0x0002
#define OPT_ABOUT			0x0100
#define OPT_VERBOSE			0x0200

#define	RB_SIMPLE_SZ		1024
#define	RB_FULL_SZ			2048

//------------------------------------------------------------------------------
// Local data
//------------------------------------------------------------------------------
static poptContext		optCon;

//------------------------------------------------------------------------------
// Local functions
//------------------------------------------------------------------------------
static void rb_simple(void);
static void rb_full(void);
static void print_statistics(RING_BUFFER_STAT* stat);
static void print_status(RING_BUFFER* rb);
static void about(void);

//------------------------------------------------------------------------------
// Main function
//------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
	uint32_t	opt=0;
	int			idx=0;

	struct poptOption optionsTable[] = {
		{ "simple",	's', POPT_ARG_NONE,	  NULL,			 's', "simple ring buffer test",			NULL	},
		{ "full",	'f', POPT_ARG_NONE,	  NULL,			 'f', "full ring buffer test",				NULL	},
		{ "about",	'a', POPT_ARG_NONE,	  NULL,			 'a', "display information about the app",	NULL	},
		{ "verbose",'v', POPT_ARG_NONE,	  NULL,			 'v', "enable verbose mode",				NULL	},
		POPT_AUTOHELP
		POPT_TABLEEND
	};

//------------------------------------------------------------------------------
//  Process arguments
//------------------------------------------------------------------------------
	optCon = poptGetContext(NULL, argc, (const char **)argv, optionsTable, 0);
	poptSetOtherOptionHelp(optCon, "[OPTIONS]*");
	if (argc == 1) {
		about();
	}
	while ((idx = poptGetNextOpt(optCon)) >= 0) {
		switch (idx) {
		case 's':
			opt |= OPT_SIMPLE;
			break;
		case 'f':
			opt |= OPT_FULL;
			break;
		case 'a':
			opt |= OPT_ABOUT;
			break;
		case 'v':
			opt |= OPT_VERBOSE;
			break;
		}
	}
	if (idx < -1) {
		fprintf(stderr, "%s: %s\n",
		        poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
		        poptStrerror(idx));
		exit(opt);
	}
	if (opt & OPT_ABOUT) {
		bldinfoPrintBldInfo();
		exit(0);
	}

//------------------------------------------------------------------------------
//  Call tests
//------------------------------------------------------------------------------
	if (opt & OPT_SIMPLE)	rb_simple();
	if (opt & OPT_FULL)		rb_full();

	return 0;
}

//------------------------------------------------------------------------------
///	\brief
///		Rinb buffer simple test
///
///	\param
///		none
///
///	\return
///		none
//------------------------------------------------------------------------------
static void rb_simple(void)
{
	RING_BUFFER	 		rb_test;
	RING_BUFFER_STAT	rb_stat;

	uint8_t*		rb_data=NULL;
	uint8_t			rb_char;

	printf("initializing ring buffer\n");
	rb_data = malloc(RB_SIMPLE_SZ);
	RingBuff_HW_Init(&rb_test, rb_data, RB_SIMPLE_SZ);
	RingBuff_OS_Init(&rb_test);
	print_status(&rb_test);
	printf("\n");

	printf("adding 'test' to ring buffer\n");
	RingBuff_Add(&rb_test, (uint8_t)'t');
	RingBuff_Add(&rb_test, (uint8_t)'e');
	RingBuff_Add(&rb_test, (uint8_t)'s');
	RingBuff_Add(&rb_test, (uint8_t)'t');
	RingBuff_GetStat(&rb_test, &rb_stat);
	print_statistics(&rb_stat);
	print_status(&rb_test);
	printf("\n");

	printf("ring buffer remove\n");
	RingBuff_Remove(&rb_test, &rb_char);
	printf("ring buffer remove, got: %c\n", rb_char);
	RingBuff_GetStat(&rb_test, &rb_stat);
	print_statistics(&rb_stat);
	print_status(&rb_test);
	printf("\n");

	printf("clearing ring buffer\n");
	RingBuff_Clear(&rb_test);
	RingBuff_GetStat(&rb_test, &rb_stat);
	print_statistics(&rb_stat);
	print_status(&rb_test);
	printf("\n");

	printf("ring buffer remove\n");
	RingBuff_Remove(&rb_test, &rb_char);
	printf("ring buffer remove, got: %c\n", rb_char);
	RingBuff_GetStat(&rb_test, &rb_stat);
	print_statistics(&rb_stat);
	print_status(&rb_test);
	printf("\n");

	printf("ring buffer fill\n");
	for (uint32_t i=0; i<RB_SIMPLE_SZ; i++)
		RingBuff_Add(&rb_test, (uint8_t)'t');
	RingBuff_GetStat(&rb_test, &rb_stat);
	print_statistics(&rb_stat);
	print_status(&rb_test);
	printf("\n");

	printf("ring buffer full test\n");
	RingBuff_Add(&rb_test, (uint8_t)'t');
	RingBuff_GetStat(&rb_test, &rb_stat);
	print_statistics(&rb_stat);
	print_status(&rb_test);
	printf("\n");

	free(rb_data);
}
//------------------------------------------------------------------------------
///	\brief
///		Ring buffer full test
///
///	\param
///		none
///
///	\return
///		none
//------------------------------------------------------------------------------
static void rb_full(void)
{
}

//------------------------------------------------------------------------------
///	\brief
///		Ring buffer print statistics
///
///	\param
///		RING_BUFFER_STAT
///
///	\return
///		none
//------------------------------------------------------------------------------
static void print_statistics(RING_BUFFER_STAT* stat)
{
	printf("ring buffer status:\n");											// header
	printf("           buffer size: %d\n", stat->buff_sz);						// print Data buffer size
	printf("         current count: %d\n", stat->curr_ct);						// print Current count
	printf("       high water mark: %d\n", stat->water_mark);					// print High water mark
	printf(" total items processed: %d\n", stat->total_ct);						// print Total number of items
	printf("  ring buff full count: %d\n", stat->rb_full_ct);					// print Ring Buffer full count
	printf(" ring buff empty count: %d\n", stat->rb_empty_ct);					// print Ring Buffer empty count
}

//------------------------------------------------------------------------------
///	\brief
///		Ring buffer print status
///
///	\param
///		RING_BUFFER
///
///	\return
///		none
//------------------------------------------------------------------------------
static void print_status(RING_BUFFER* rb)
{
	char*	st = NULL;

	switch (RingBuff_GetStatus(rb)) {
	case RB_RESET:
		st = "reset";
		break;
	case RB_OK:
		st = "ok";
		break;
	case RB_EMPTY:
		st = "empty";
		break;
	case RB_FULL:
		st = "full";
		break;
	default:
		st = "unknown";
		break;
	}
	printf("ring buffer status: %s\n",st);
}

//------------------------------------------------------------------------------
///	\brief
///		Display about
///
///	\param
///		none
///
///	\return
///		none
//------------------------------------------------------------------------------
static void about(void)
{
	bldinfoPrintBldInfo();
	poptPrintUsage(optCon, stderr, 0);
	exit(1);
}

//
//  End: rb-test.c
//
